import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
//import java.util.List;
//import java.util.Set;
//import java.util.Vector;

import au.com.bytecode.opencsv.CSVReader;

public class TransitGraph {
	public final String ctastopsFileName = "CTA_revised.csv";
	public final String scheduleFileName = "concise_schedule.csv";
	private final HashMap<Integer, Station> stations;
	private final HashMap<Integer, Edge> edges;

	public TransitGraph() {
		stations = new HashMap<Integer, Station>();
		edges = new HashMap<Integer, Edge>();
		try {
			System.out.println("Loading stations...");
			updateStations();
			createParentStations();
			System.out.println("Done loading stations.");
			
			System.out.println("Loading schedule...");
			updateSchedule();
			System.out.println("Done loading schedule.");
			
			System.out.println("Loading edges...");
			updateEdges();
			System.out.println("Done loading edges.");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public TransitGraph(HashMap<Integer, Station> stations, HashMap<Integer, Edge> edges) {
		this.stations = stations;
		this.edges = edges;
	}
	
	public Station getStation(int id) {
		return stations.get(id);
	}
	
	public void updateStations() throws IOException {
		 CSVReader reader = new CSVReader(new FileReader(ctastopsFileName));

			String[] line = reader.readNext();
			//DEBUG
			/*for (String string : line) {
				System.out.print(string + " ");
			}*/
			
			line = reader.readNext(); // Skip the header
			
			//DEBUG
			//System.out.println();

			Integer st_count = 0;
			
			Double maxLon=-Double.MAX_VALUE,minLon=Double.MAX_VALUE,maxLat=-Double.MAX_VALUE,minLat=Double.MAX_VALUE;
			
			while (line != null) {
				Double lon = new Double(line[4]);
				Double lat = new Double(line[5]);
				
				/* maxLon = Math.max(lon,maxLon);
				 minLon = Math.min(lon,minLon);
				 maxLat = Math.max(lat,maxLat);
				 minLat = Math.min(lat,minLat);*/
				
				
				for(int n = 6; n <=14 ; n++) {
					
					if(line[n].equals("1")) {
						String line_color = null;
						
						if (n == 6) {line_color = "Red";}
						if (n == 7) {line_color = "Blue";}
						if (n == 8) {line_color = "Brn";}
						if (n == 9) {line_color = "G";}
						if (n == 10) {line_color = "P";}
						if (n == 11 && !line[10].equals("1")) {line_color = "P";}
						if (n == 11 && line[10].equals("1")){continue;}
						if (n == 12) {line_color = "Y";}
						if (n == 13) {line_color = "Pink";}
						if (n == 14) {line_color = "Org";}
						
						Station st = new Station(new Integer(line[0]), new Integer(line[1]), line[2], line[3],
								lon, lat, line_color);
						stations.put(st.hashCode(), st);
						st_count++;
						
						//DEBUG
						//System.out.print(st_count + ") ");
						//System.out.println(st.toString());
					}
				}

				line = reader.readNext();
			}
			
			/*System.out.println(maxLon+","+minLon+","+maxLat+","+minLat);
			
			OSMMercator mercator = new OSMMercator((minLat+maxLat)/2.0, (minLon+maxLon)/2.0, 1.05*(maxLon-minLon)/width, width, height);
			for (Station st : stations) {
				st.setLon(mercator.x(st.getLon()));
				st.setLat(mercator.y(st.getLat()));
			}*/
			
			System.out.println("Number of stations: " + st_count);
	}
	
	public void createParentStations() {
		ArrayList<Station> stations_array = getStationsList();
		for(Station st : stations_array) {
			String parent_id = "" + st.getParentid();
			if(!stations.containsKey(parent_id.hashCode())) {
				ParentStation new_parent = new ParentStation(st.getParentid(), st.getParentid(), st.getName(), "", st.getLon(), st.getLat(), "");
				stations.put(new_parent.hashCode(), new_parent);
			}
		}
	}
	
	public void updateSchedule() throws IOException {
		CSVReader reader = new CSVReader(new FileReader(scheduleFileName));
		
		String[] line = reader.readNext();
		line = reader.readNext(); // skip the header
		
		while (line != null) {
			
			String id = line[0]+line[1];
			Station st = stations.get(id.hashCode());
			
			//System.out.print(id + " ");
			st.addTime(line[2]);
			
			/*for( String str : line) {
				System.out.print(str + " ");
			}*/
			//System.out.println(line[2]);
			
			line = reader.readNext();
		}
		
	}
	
	public void updateEdges() throws IOException {

		Integer ed_count = 0;
		
		ArrayList<Station> stations_array = getStationsList();
	//transfers	
		for(Station src : stations_array) {
			for(Station dest : stations_array) {
				if(!src.equals(dest) && src.sibling(dest) && !(src instanceof ParentStation) && !(dest instanceof ParentStation)) {
					Edge edge = new Edge(src, dest, true, 0); // zero value means weight hasn't been set
					addEdge(edge);
					ed_count++;
					//System.out.println(edge);
				}
			}
		}
		
	//transfers where walking is involved with assumption of 0 walk time
		String transfers = "edges/transfers.csv";
		String [] nextLine;
		//Integer weight;
		//Double test;
		//String srcid,destid;
		Station src;
		Station dest;
		
		CSVReader reader = new CSVReader(new FileReader(transfers));
		
		nextLine = reader.readNext();
		
		//String [] line = {null,null};
		while((nextLine = reader.readNext()) != null) {
			
			src = stations.get(nextLine[0].hashCode());
			dest = stations.get(nextLine[1].hashCode());
			Edge edge = new Edge(src, dest, true, 0);
			addEdge(edge);
			ed_count++;
			
		}
		
		reader.close();
		
		String blue_edges_forestPark = "edges/blue_edges_Forest Park.csv";
		String blue_edges_ohare = "edges/blue_edges_O'hare.csv";
		String brown_edges_kimball = "edges/brown_edges_kimball.csv";
		String brown_edges_loop = "edges/brown_edges_loop.csv";
		String green_edges_63rd = "edges/green_edges_63rd.csv";
		String green_edges_harlem = "edges/green_edges_harlem.csv";
		String orange_edges_loop = "edges/orange_edges_loop.csv";
		String orange_edges_midway = "edges/orange_edges_midway.csv";
		String pink_edges_54th = "edges/pink_edges_54th.csv";
		String pink_edges_loop = "edges/pink_edges_loop.csv";
		String purple_edges_howard = "edges/purple_edges_howard.csv";
		String purple_edges_linden = "edges/purple_edges_linden.csv";
		String red_edges_95th = "edges/red_edges_95th.csv";
		String red_edges_howard = "edges/red_edges_howard.csv";
		String yellow_edges_howard = "edges/yellow_edges_howard.csv";
		String yellow_edges_skokie = "edges/yellow_edges_skokie.csv";
		String innerloop_edges = "edges/innerloop_edges.csv";
		String pexp_edges_loop = "edges/pexp_edges_loop.csv";
		String pexp_edges_howard = "edges/pexp_edges_howard.csv";
		
		ed_count = edgesHelper(blue_edges_forestPark, "Blue", ed_count);
		ed_count = edgesHelper(blue_edges_ohare, "Blue",ed_count);
		ed_count = edgesHelper(brown_edges_kimball, "Brn",ed_count);
		ed_count = edgesHelper(brown_edges_loop, "Brn",ed_count);
		ed_count = edgesHelper(green_edges_63rd, "G",ed_count);
		ed_count = edgesHelper(green_edges_harlem, "G",ed_count);
		ed_count = edgesHelper(orange_edges_loop, "Org",ed_count);
		ed_count = edgesHelper(orange_edges_midway, "Org",ed_count);
		ed_count = edgesHelper(pink_edges_54th, "Pink",ed_count);
		ed_count = edgesHelper(pink_edges_loop, "Pink",ed_count);
		ed_count = edgesHelper(purple_edges_howard, "P",ed_count);
		ed_count = edgesHelper(purple_edges_linden, "P",ed_count);
		ed_count = edgesHelper(red_edges_95th, "Red",ed_count);
		ed_count = edgesHelper(red_edges_howard, "Red",ed_count);
		ed_count = edgesHelper(yellow_edges_howard, "Y",ed_count);
		ed_count = edgesHelper(yellow_edges_skokie, "Y",ed_count);
		ed_count = edgesHelper(innerloop_edges,"P",ed_count); //Pexp
		ed_count = edgesHelper(innerloop_edges,"Pink",ed_count);
		ed_count = edgesHelper(innerloop_edges,"Org",ed_count);
		ed_count = edgesHelper(pexp_edges_loop,"P",ed_count);//Pexp
		ed_count = edgesHelper(pexp_edges_howard,"P",ed_count);//Pexp
				
		System.out.println("Number of edges: " + ed_count);
		
	}
	
	private Integer edgesHelper(String line_edge, String line, Integer ed_count) throws IOException {
		
		CSVReader reader = new CSVReader(new FileReader(line_edge));
		
		String [] nextLine;
		Integer weight;
		Double test;
		String srcid,destid;
		Station src;
		Station dest;
		
		nextLine = reader.readNext();
		
		//debugging
		//System.out.println(nextLine[0] + "," + nextLine[1] + "," + nextLine[2]);
		
		while( (nextLine = reader.readNext()) != null ) {
			
			srcid = nextLine[0]+line;
			destid = nextLine[1]+line;
			src = stations.get(srcid.hashCode());
			dest = stations.get(destid.hashCode());
			if( nextLine[2].equals("1.5") || nextLine[2].equals(".5") || nextLine[2].equals("2.5")) {
				
				test = new Double(nextLine[2]);
				test += 0.5;
				weight = test.intValue();
				
			}
			else
				weight = new Integer(nextLine[2]);
			Edge edge = new Edge(src, dest, false, weight);
			addEdge(edge);
			ed_count++;
			//System.out.println(edge);
			
		}
		
		return ed_count;
		
	}
	
	public ArrayList<Station> getStationsList() {
		ArrayList list = new ArrayList(stations.values());	
		return list;
	}
	
	public HashMap<Integer, Station> getStations() {
		return stations;
	}

	public void addEdge(Edge edge) {
		edges.put(edge.hashCode(), edge);
	}
	
	public Edge getEdge(int key) {
		return edges.get(key);
	}
	
	public boolean containsEdge(int key) {
		return edges.containsKey(key);
	}
	
	public void removeEdge(Edge to_remove) {
		edges.remove(to_remove.hashCode());
	}
	
	public ArrayList<Edge> getEdges() {
		ArrayList list = new ArrayList(edges.values());	
		return list;
	}
	
	
	
}